﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LongNet.Util
{
    /// <summary>
    /// Provides a set of static methods for extensions.
    /// </summary>
    public static class GenericExtensions
    {
        #region Static Methods

        /// <summary>
        /// Creates a copy of the current source.
        /// </summary>
        /// <remarks>The source to be cloned must be serializable.</remarks>
        /// <typeparam name="T">The type of source.</typeparam>
        /// <param name="source">The source object.</param>
        /// <returns>A copy of the source.Null will be return if source is null or 
        /// <see cref="KudyNet.Unity.Serializer.CanBinarySerialize"/> is false.</returns>
        public static T Clone<T>(this T source)
        {
            return Serializer.CloneObject<T>(source);
        }

        /// <summary>
        /// Checks whether the source is in the list or ont.
        /// </summary>
        /// <typeparam name="T">The type that is equatable of source.</typeparam>
        /// <param name="source">The source element.</param>
        /// <param name="list">A enumerable list.</param>
        /// <returns></returns>
        public static bool In<T>(this T source, params T[] list) where T : IEquatable<T>
        {
            return list.Any(i => i.Equals(source));
        }

        /// <summary>
        /// Checks whether the source is in the list or ont.
        /// </summary>
        /// <typeparam name="T">The type that is equatable of the source.</typeparam>
        /// <param name="source">The source element.</param>
        /// <param name="list">A enumerable list.</param>
        /// <returns></returns>
        public static bool In<T>(this T source, IEnumerable<T> list) where T : IEquatable<T>
        {
            return list.Any(i => i.Equals(source));
        }


        /// <summary>
        /// Checks whether the source is between min and max or ont.
        /// </summary>
        /// <typeparam name="T">The type that is comparable of the source.</typeparam>
        /// <param name="source">The source element.</param>
        /// <param name="min">The min element.</param>
        /// <param name="max">The max element.</param>
        /// <returns></returns>
        public static bool InRange<T>(this T source, T min, T max) where T : IComparable<T>
        {
            return source.CompareTo(min) >= 0 && source.CompareTo(max) <= 0;
        }

        /// <summary>
        /// Performs the specified action on each element of the enumerable list.
        /// </summary>
        /// <typeparam name="T">The type of elements in the source.</typeparam>
        /// <param name="source">A enumerable list.</param>
        /// <param name="action">The System.Action&lt;T&gt; delegate to perform on each element of the source.</param>
        public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
        {
            foreach (T element in source)
            {
                T e = element;
                action(e);
            }
        }

        /// <summary>
        /// Performs the specified action on each element of the enumerable list, 
        /// with the int variable auto-increment in action. 
        /// </summary>
        /// <typeparam name="T">The type of elements in the source.</typeparam>
        /// <param name="source">A enumerable list.</param>
        /// <param name="action">The System.Action&lt;T, int&gt; delegate to perform on each element of the source.</param>
        public static void ForEach<T>(this IEnumerable<T> source, Action<T, int> action)
        {
            int i = 0;
            foreach (T element in source)
            {
                i++;
                T e = element;
                action(e, i);
            }
        }

        /// <summary>
        /// Converts a KeyValuePair&lt;string, string&gt; collection to url 
        /// query string (e.g. q1=v1&amp;q2=v2&amp;qn=vn).
        /// </summary>
        /// <param name="source">A KeyValuePair&lt;string, string&gt; collection</param>
        /// <returns></returns>
        public static string ToQueryString(this IEnumerable<KeyValuePair<string, string>> source)
        {
            return Utils.ToQueryString(source);
        }

        /// <summary>
        /// Combines the items in an enumerable collection with the comma(,).
        /// </summary>
        /// <typeparam name="T">The type of items in the collection.</typeparam>
        /// <param name="source">An enumerable collection.</param>
        /// <returns>The combined string.</returns>
        public static string ToCommaString<T>(this IEnumerable<T> source)
        {
            return Utils.CombineCollection<T>(source, ",", null, null);
        }

        /// <summary>
        /// Combines the items in an enumerable collection with a separator.
        /// </summary>
        /// <typeparam name="T">The type of items in the collection.</typeparam>
        /// <param name="source">An enumerable collection.</param>
        /// <param name="separator">The separator to combine the collection items with.</param>
        /// <returns>The combined string.</returns>
        public static string Combine<T>(this IEnumerable<T> source, string separator)
        {
            return Utils.CombineCollection<T>(source, separator, null, null);
        }

        /// <summary>
        /// Combines the items in an enumerable collection with a separator, each item 
        /// will be fixed with the specified prefix and suffix.
        /// </summary>
        /// <typeparam name="T">The type of items in the collection.</typeparam>
        /// <param name="source">An enumerable collection.</param>
        /// <param name="separator">The separator to combine the collection items with.</param>
        /// <param name="prefix">The prefix to fix the collection items with.</param>
        /// <param name="suffix">The suffix to fix the collection items with.</param>
        /// <returns>The combined string.</returns>
        public static string Combine<T>(this IEnumerable<T> source, string separator, string prefix, string suffix)
        {
            return Utils.CombineCollection<T>(source, separator, prefix, suffix);
        }

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="pageSize"></param>
        /// <param name="pageIndex"></param>
        /// <returns></returns>
        public static PaginatedList<T> ToPaginatedList<T>(this IEnumerable<T> source, int pageSize, int pageIndex)
        {
            return new PaginatedList<T>(source, pageSize, pageIndex);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="recordCount"></param>
        /// <param name="pageSize"></param>
        /// <param name="pageIndex"></param>
        /// <returns></returns>
        public static PaginatedList<T> ToPaginatedList<T>(this IEnumerable<T> source, int recordCount, int pageSize, int pageIndex)
        {
            return new PaginatedList<T>(source, recordCount, pageSize, pageIndex);
        }
    }
}
